# Godot-Modbus Demo

## Modbus? For Godot? Seriously? Why?

Well, just how Spacechem, Infinifactory and other Zachtronics games are a fun way to learn about basic programming technics and test one's logic at competition-grade tasks, one can try learning about industrial control tools via puzzles as well. 

The whole idea is to make Godot simulate industrial devices and expose them as network ports so you can use any modbus-capable industrial control suite out there, including PLCs and even your own python scripts to try and make the puzzle work.

It doesn't even matter if tools are opensource or not, they just need to be able to send packets. ^^

So if you are really into industrial control and want to see how hard are different tools to get into /use you can try different tools for your favourite puzzle and decide what tool makes your day easier! Kind of a convenience benchmark really.

No actual levels are there yet though, it is just a technical demo, but it is not hard to make both devices and levels of your own if you know Godot. This is all very simple really.

## Ok, how this works?:

To be able to connect via modbus, [libmodbus](https://github.com/stephane/libmodbus) is used as the lowest level.

For Godot engine, ability to use libmodbus is added by writing a shared object compiled against GDNative API - this allows Godot to call C functions from its usual GDscript internal scripting interface without the need to recompile the whole engine (unlike C/C++ modules that need to be compiled into engine itself).

Inside a shared object it is barebones modbus functionality like register and coil IO and starting a server which listens on a socket. 

In Godot, this functionallity is then called from the base GDscript class `ModbusServer`, which for cleaner configuration is then used by `ModbusSpatial` which inherits a `Spatial` node (i.e. is placeable on the scene) and exposes bind IP and port settings so they are editable from the editor when you place it.

`ModbusSpatial` is then inherited by all controllable devices which use this inheritance to send or receive data via modbus protocol. Connection parameters of every one of them can be set by just clicking on sensor/actuator and editing bind IP and port fields.

Aside from using ModbusSpatial to send and receive some data, controllable devices are perfectly normal godot game objects, and also demo includes a conveyor and box spawner that are not modbus-controllable.

## Modbus demostrating devices

* **Sensor** is a distance sensor that outputs distance in units x 100 (game scene is grid-based in this demo)
	* It writes the resulting distance integer to the holding register of offset 0.
* **Pusher** is a simple modbus coil driven device. It tries to extends when coil (at offset 0) is 1 and tries to contract when coil is 0.

## Setting stuff up!

### 1. Install godot and libmodbus on your host machine.

#### on Arch Linux and Manjaro:

```
sudo pacman -S godot
```

libmodbus can be fetched from AUR [https://aur.archlinux.org/packages/libmodbus-git/](https://aur.archlinux.org/packages/libmodbus-git/)

#### on Debian:

```
sudo apt install godot3 libmodbus5 libmodbus-dev
```

### 2. Clone this repository

```
git clone https://notabug.org/Houkime/godot-modbus-demo
cd godot-modbus-demo
git submodule update --init
```

### 3. Compile

```
make
```

### 4. Edit connection parameters

```
cd simple
godot -e Pushertest.tscn
```

* Click on sensor (blue), and set network parameters you want on the left.

![](https://notabug.org/Houkime/godot-modbus-demo/raw/master/screenshots/sensor-screen_scaled.png)

Port is arbitrary, just don't let ports of different devices collide.

* Same for the pusher (orange)
![](https://notabug.org/Houkime/godot-modbus-demo/raw/master/screenshots/pusher-screen_scaled.png)

* Save with ctrl+S or whatever

**Alternatively** you can do the same by opening scene file in vim or your other (blasphemy!) favourite editor.

For example, the pusher looks like this, so you can just edit 2 last lines, adding lines if sth is missing (godot does not save settings that are set to their default values, for example default ip is 127.0.0.1)

```
[node name="Pusher" type="Spatial" parent="."]
transform = Transform( -8.14603e-08, 0, -0.5, 0, 0.5, 0, 0.5, 0, -8.14603e-08, 5, 1, -1 )
script = ExtResource( 1 )
address = "192.168.0.1"
port = 5040
```

And Sensor is called Sensor!

_(TODO: address should really be called sth like bind-ip but i am not sure this is intuitive)_

However, even if you're going text route, there is no CLI option for Godot to reimport assets (at least a direct one, which is a shame). You will have trouble if trying running right away without doing `godot -e Main.tscn` (it does reimporting by itself, you can close then).

### 5. Run

Run with f5 with editor open (at Main.tscn, not Pushertest.tscn) or from terminal `godot Main.tscn` 

_Note: cd into the 'simple' folder if necessary - something inside Godot depends on terminal calling these commands from the folder and giving subtle errors in other cases, so you can't always do simple/Main.tscn from godot-modbus-demo_

Devices don't do anything by themselves, but `lsof -i` should report related ports as listening.

You can then use any tool to connect and try do sth interesting.

**HAVE A BLAST!**
